use lazy_static::lazy_static;
use log::{error, info};
use rocket::{get, post};
use serde::{Deserialize, Serialize};
use ysbase::func::parse_xml;
use ysbase::mp::{EncryptRequestData, TextMessage, TextResponse, ToXml, WechatMp};

lazy_static! {
    static ref WECHAT_MP: WechatMp = WechatMp::new(
        std::env::var("WECHAT_TOKEN").expect("WECHAT_TOKEN must be set"),
        std::env::var("WECHAT_APPID").expect("WECHAT_APPID must be set"),
        std::env::var("WECHAT_SECRET").expect("WECHAT_SECRET must be set"),
        std::env::var("WECHAT_AES_KEY").expect("WECHAT_AES_KEY must be set")
    );
}

#[get("/")]
pub async fn index() -> &'static str {
    "Hello, bakeries!"
}

// api 校验入口
#[get("/api?<echostr>&<signature>&<timestamp>&<nonce>")]
pub async fn check_signature(
    echostr: &str,
    signature: &str,
    timestamp: &str,
    nonce: &str,
) -> String {
    if WECHAT_MP.check_signature(signature, timestamp, nonce) {
        echostr.to_string()
    } else {
        "failed".to_string()
    }
}

#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "PascalCase")]
#[serde(rename = "xml")]
struct MsgBase {
    pub msg_type: String,
    pub from_user_name: String,
    pub to_user_name: String,
}

// api 消息处理入口
#[post(
    "/api?<timestamp>&<nonce>&<msg_signature>&<signature>&<openid>",
    data = "<data>"
)]
pub async fn api_message(
    timestamp: &str,
    nonce: &str,
    msg_signature: Option<&str>,
    signature: &str,
    openid: &str,
    data: String,
) -> String {
    info!("api_message timestamp: {}, nonce: {}, msg_signature: {:?}, signature: {}, openid: {}, data: {}", timestamp, nonce, msg_signature, signature, openid, data);

    let is_encrypt = msg_signature.is_some();

    let body_str = if is_encrypt {
        // 加密信息还有一些问题, TODO
        let encrypt_data: EncryptRequestData = parse_xml(&data);
        let result = WECHAT_MP.decrypt_message(
            &encrypt_data.encrypt,
            msg_signature.unwrap(),
            timestamp,
            nonce,
        );
        match result {
            Ok(body) => body,
            Err(e) => {
                error!("decrypt_message error: {}", e);
                panic!("decrypt_message error: {}", e);
            }
        }
    } else {
        data
    };

    let base: MsgBase = parse_xml(&body_str);
    let response = match base.msg_type.as_str() {
        "text" => {
            let text_msg: TextMessage = parse_xml(&body_str);
            let content = format!("信息：{}", text_msg.content);
            TextResponse::new(&base.from_user_name, &base.to_user_name, &content)
        }
        _ => {
            let content = "发生错误了，请联系管理员！";
            TextResponse::new(&base.from_user_name, &base.to_user_name, &content)
        }
    };

    if is_encrypt {
        WECHAT_MP
            .encrypt_message(&response)
            .expect("encrypt_message error")
    } else {
        response.to_xml()
    }
}

#[get("/get_access_token")]
pub async fn get_access_token() -> String {
    let getter = WECHAT_MP.access_token_getter();
    getter.get_token().await.unwrap()
}
